/* 包含头文件-----------------------------------------------------------------*/
#include "rcc.h"

/* 私有宏定义-----------------------------------------------------------------*/
#define RCC_CLOCK_SOURCE                (0u) /* 0:内部时钟HSI  1:外部时钟HSE */
#define RCC_SYSTICK_EN                  (1u) /* 0:不开启 1:开启 */
#define RCC_ADC_CLOCK_EN                (0u) /* 0:不开启 1:开启 */

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/
static uint16_t delayMsCnt, delayUsCnt;

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/


/* 注释掉位于stm32f10x_it.c文件中的SysTick_Handler函数
   在别的地方复现此函数  滴答定时器中断函数
void SysTick_Handler(void)
{
    // user handle write here
}
*/

/**
  * @brief  系统时钟初始化
  * @note   外部晶振8MHz
  * @param  sysclk : 时钟频率MHz(4的倍数)(HSI 8~64)(HSE 8~64和72)
  * @retval 0:时钟初始化成功 1:非法参数
  */
uint8_t rcc_system_clock_config(uint8_t sysclk)
{
#if (RCC_CLOCK_SOURCE)
    if(64 < sysclk && 72 != sysclk) { return 1; }
    if(0 != (sysclk % 4) || 8 > sysclk || 72 < sysclk) { return 1; }
#else
    if(0 != (sysclk % 4) || 8 > sysclk || 64 < sysclk) { return 1; }
#endif
    
    RCC_DeInit();

#if (RCC_CLOCK_SOURCE)
    RCC_HSEConfig(RCC_HSE_ON); /* 打开外部高速时钟HSE */
    while(RESET == RCC_GetFlagStatus(RCC_FLAG_HSERDY)); /* 等待时钟稳定 */
#else
    RCC_HSICmd(ENABLE); /* 打开内部高速时钟HSI */
    while(RESET == RCC_GetFlagStatus(RCC_FLAG_HSIRDY)); /* 等待时钟稳定 */
#endif
    
    RCC_HCLKConfig(RCC_SYSCLK_Div1); /* AHB clock(HCLK) = SYSCLK/1 (max:72MHz) */
    
    RCC_PCLK1Config(RCC_HCLK_Div2); /* APB1 clock(PCLK1) = HCLK/2 (max:36MHz) */
    
    RCC_PCLK2Config(RCC_HCLK_Div1); /* APB2 clock(PCLK2) = HCLK/1 (max:72MHz) */

    /* SYSCLK <= 24MHz  0等待周期 */
    if(24 >= sysclk)
    {
        FLASH_SetLatency(FLASH_Latency_0);
    } /* 24MHz < SYSCLK <= 48MHz  1等待周期 */
    else if(48 >= sysclk)
    {
        FLASH_SetLatency(FLASH_Latency_1);
    } /* 48MHz < SYSCLK <= 72MHz  2等待周期 */
    else
    {
        FLASH_SetLatency(FLASH_Latency_2);
    }
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); /* 使能FLASH预取缓冲区 */
    
#if (RCC_CLOCK_SOURCE)
    /* SYSCLK <= 64MHz  PLLCLK = (8MHz/2)*(SYSCLK/4) */
    if(64 >= sysclk)
    {
        RCC_PLLConfig(RCC_PLLSource_HSE_Div2, (sysclk / 4 - 2) * RCC_PLLMul_3);
    } /* SYSCLK == 72MHz  PLLCLK = 8MHz*9 */
    else
    {
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    }
#else
    RCC_PLLConfig(RCC_PLLSource_HSI_Div2, (sysclk / 4 - 2) * RCC_PLLMul_3); /* PLLCLK = (8MHz/2)*(SYSCLK/4) */
#endif
    RCC_PLLCmd(ENABLE); /* 使能PLL */
    while(RESET == RCC_GetFlagStatus(RCC_FLAG_PLLRDY)); /* 等待PLL稳定 */
    
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); /* 选择PLLCLK作为SYSCLK时钟源 */
    while(0x08 != RCC_GetSYSCLKSource()); /* 等待SYSCLK时钟源切换完成 */

#if (RCC_SYSTICK_EN)
    SysTick_Config(sysclk * 1000); /* systick初始化周期1ms */
#endif
    
#if (RCC_ADC_CLOCK_EN)
    /* 设置ADC时钟分频系数 */
    if(28 >= sysclk)
    {
        RCC_ADCCLKConfig(RCC_PCLK2_Div2);
    }
    else if(56 >= sysclk)
    {
        RCC_ADCCLKConfig(RCC_PCLK2_Div4);
    }
    else
    {
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);
    }
#endif
    
    /* 根据主频计算延时因子 */
    if(24 >= sysclk)
    {
        delayMsCnt = sysclk * 123;
        delayUsCnt = sysclk / 8;
        if(!delayUsCnt) { delayUsCnt = 1; }
    }
    else if(48 >= sysclk)
    {
        delayMsCnt = sysclk * 111;
        delayUsCnt = sysclk / 9;
    }
    else
    {
        delayMsCnt = sysclk * 100;
        delayUsCnt = sysclk / 10;
    }
    
    return 0;
}

/**
  * @brief  输出各时钟频率信息
  * @param  None
  * @retval None
  */
void rcc_system_clock_debug(void)
{
    RCC_ClocksTypeDef clock;
    
    RCC_GetClocksFreq(&clock);
    
    /*
    printf("SYSCLK:%dHz, HCLK:%dHz, PCLK1:%dHz, PCLK2:%dHz\r\n", clock.SYSCLK_Frequency, clock.HCLK_Frequency, clock.PCLK1_Frequency, clock.PCLK2_Frequency);
    */
}

/**
  * @brief  ms延时(粗略)
  * @param  ms : 延时时间ms
  * @retval None
  */
void rcc_delay_ms(uint32_t ms)
{
    volatile uint32_t cnt = 0;
    volatile uint32_t msCnt = ms;
    
    while(msCnt--)
    {
        cnt = delayMsCnt;
        while(cnt--);
    }
}

/**
  * @brief  us延时(粗略)
  * @param  us : 延时时间us
  * @retval None
  */
void rcc_delay_us(uint32_t us)
{
    volatile uint32_t usCnt = us * delayUsCnt;
    
    while(usCnt--);
}
